home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Games of Daze
/
Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso
/
x2ftp
/
msdos
/
pmode
/
code32
/
start32.doc
< prev
next >
Wrap
Text File
|
1993-01-08
|
15KB
|
318 lines
Hi folks, this is Tran... This text explains START32, my 386 protected
mode header... I'm assuming youre an assembler programmer. If you are not,
this thing will do you no good. I'm also assuming you have some experience,
and knowledge of the 386 wouldn't hurt either... If you don't know the 386,
I suggest you get a good book if you really want to code it...
First of all:
-------------
I coded START32 for myself, it is designed and optimized for my needs. The
greatest of which is the need for speed... That is the reason I do not
implement paging in this thing, too slow... Also, since the only real mode
INTs I usually need are DOS file functions, the V86 handler is not perfect,
but it does DOS and BIOS just fine.
What it does:
-------------
START32 is a piece of code that handles most of the things associated with
using and getting into and out of 32bit protected mode. It also allows your
protected mode programs to access the regular real-mode DOS and BIOS functions.
START32 will check mundane little things like the processor and memory, then
if the system is 386+ and not already in protected mode, it will switch the
system into 32bit protected mode. In protected mode the system will run in
flat memory, that is you won't need to bother with segment registers, and
large data arrays will be much easier to handle...
How the system works:
---------------------
After START32 initializes protected mode, it will jump to a label '_main',
which mush be declared public in your code. This is the starting point of your
program. All of the code and data in your program will reside in one large
segment called 'code32' ... this is a 4gig segment. You do regular code using
the 386 instruction set. To access a real-mode interrupt function, you load
up 'virtual registers' with the values you want passed to the interrupt, then
you load up AL with the number of the interrupt you wanna call, then you call
INT 30h. The system will use the 386's v86 mode to call the real mode int.
After which, the values in the 'virtual regs' will be what the interrupt
handler passed back (All the real registers are preserved).
Selectors:
----------
Instead of physical segment pointers, in protected mode, the 386 uses
selectors. Selectors are indexes into a table of data that describe the
memory location the specific index points to. But you need not concern
yourself with these tables (GDT, IDT, LDTs)... This thing takes care of them.
All you need to know, is that there are 3 basic selectors available to you.
8, 10h, and 18h... 8 is the selector for the code segment, this is the 4gig
segment which you put all your flat code into. 10h is the selector for the
data segment, the memory is physically the same as the code segment, but
it must be done this way. That is 8 and 10h point to the same large segment,
but CS must use 8, and the data segregs must use 10h... 18h is a data
selector that points to the beginning of memory. 8 and 10h both start at the
beginning of the segment 'code32' in memory, wherever it may be. But 18h
always starts at absolute physical adress 0000:0000... This is in case you
want to access something that resides before the beginning of the 32bit code,
like the BIOS data area or the PSP... Upon arrival at '_main', CS ofcourse is
8. DS, ES, FS, and SS are 10h. And GS is 18h. And you should keep them this
way because START32, whose job is by far not done after it passes control to
your code, expects it this way.
IRQs:
-----
START32 handles IRQs for both the real system, and your protected mode code.
By default, all the IRQ functions point to a piece of code in START32 which
redirects them to their real-mode handler. You can set your own protected mode
IRQ handlers, and control will pass DIRECTLY to them when they are called.
There are four possible scenarios between the type of IRQ handler and the
mode the IRQ was called in. The handling procedure can be the original real
mode handler, or your own protected mode handler. And the IRQ can occur in
protected mode, or when the system is servicing a V86 real mode INT. For
this reason, your protected mode IRQ handler should make no assumption about
the state of the system. That is, upon entry your handler, the only things
you can be sure of, is CS=8, and SS=10h... You must set the other segregs
manually if you wish to use them. Also, you must remember to terminate your
IRQ routine with an 'IRETD' instead of an 'IRET'. If you wish to call the
original real mode handler from your protected mode handler, simply call the
real mode int associated with that IRQ from your handler.
BTW: No real mode interrupt vektor table entries are modified by START32, all
the IRQs go through the IDT.
Also: START32 will mask off IRQ 0 and 1 when it first starts. The system timer
and keyboard IRQs, because there is really no use for them untill you put
them to use.
Memory:
-------
Like I said, the whole system uses flat memory when you use START32. There
are 2 types, low memory - below 640k, and high memory - above 1M... START32
does some very basic 'memory management', if you could call it that. You
can request blocks of a certain size, and START32 will either give ya a
pointer to the block, or tell ya theres not enough of that type of memory.
The blocks are allocated from the bottom up. You cannot free a memory below
an area that you allocated later. You CAN free memory though, simply by
decreasing the 'base of memory' pointer START32 uses to track the current
base of usable memory. This pointer (along with a few others) is made available
to your program. One good way of using this in a function, is along with any
registers you PUSH, you also PUSH the pointer to the type of memory you
wanna use. After the function is done and there is no more use for the memory
it has allocated, you POP the pointer. If you need any memory area permanently
throught the program, you should allocate it at the beginning, and ofcourse
never decrease the pointer beyond this area.
Crashes:
--------
One thing about coding protected mode, you do not have the use of a
debugger in finding bugz... Youre gonna have to make due with your own traps
and internal debug aids... But a crash in protected mode is not as bad as in
real mode. START32 handles the 386 exceptions. If any type of exception
occurs, START32 will stop the program, do a debug dump of the exception
number, registers, and stack ... and quit to DOS... The system will very
rarely lock up, and the DOS environment will hardly ever be screwed up...
Some reasons are that like I said, no real mode interrupt vektors are
modified, and any area below the beginning of your program is usually only
accessible through GS. This means that when your code goes astray, it cant
overwrite DOS of the int vect table, or any TSRs below it, or anything. And
there is hardly ever anything that can be screwed up above a program. An
exception will usually occur very soon after a screwup in your code. Two of
the most common exceptions are:
6 - an invalid opcode. Either something overwrote your code, or you code
jumped off into limbo...
0dh - a general protection violation. Many things can cause this.
The system itself:
------------------
First of all, START32 expects: CS=8, DS=ES=SS=FS=10h, GS=18h, and the
direction flag cleared when you call any of its functions.
In the included source code, at the top, the values are:
LOWMIN - the minimum amount of free low memory (minus the code) that
has to be present for START32 to allow the program to run.
EXTMIN - the minimum amount of extended memory that has to be present
for START32 to allow the program to run. (START32 will also quit
if it finds less than 638k total low memory).
TSTAK - the total stack space for START32 to give. The default value of
400h bytes is usually enough, unless you plan to do recursion.
ISTAK - the amount of stack space to be given to a protected mode IRQ
handler when an IRQ comes from V86 mode. (This also includes
START32's exception handlers).
START32 detects and will not run if a VGA is not present. This is not some
system critical thing, but like I said, I wrote START32 for myself, and since
I dont code anything that doesnt require a VGA right now, this is technically
part of the system for me.
START32 makes these variables available to your program:
_totalextmem:word - The total amount of extended memory in the system (in K).
_code16a:dword - Offset of the beginning of the program from absolute 0.
This starts 100h bytes above the PSP.
_code32a:dword - Offset of the beginning of protected mode code from
absolute 0. This is useful for creating realative pointers
to physical locations. That is if you wanted a pointer to
the beginning of the VGA grafix area, realative to DS,
move 0A0000h into a reg, then subtract _code32a from it.
theres a macro provided to create such pointers, @rlp.
_hextbl:bytes - Simply '0123456789ABCDEF'. It is used during an exception
dump, but since it's there, might as well make it public
since its so useful in printing hex numbers.
_lomembase:dword - Current base of low memory (as a realative pointer, like
all the other regular pointers in your code)... this is
the beginning of free low memory that has not been
allocated.
_lomemtop:dword - Top of low memory as a realative pointer.
_himembase:dword - Base of high memory, just like _lomembase.
_himemtop:dword - Guess...
v86r_ax, v86r_bx, v86r_cx, v86r_dx, v86r_si, v86r_di, v86r_bp, v86r_ds,
v86r_es, v86r_ah, v86r_al, v86r_bh, v86r_bl, v86r_ch, v86r_cl, v86r_dh,
v86r_dl, v86r_flags
These are the 'virtual registers' you use to communicate with real-mode
ints... v86r_flags though is used only to pass BACK flags, flags are not
set to it before invoking the V86 int...
Here are some 'functions':
------------------------------------------------------------------------------
_exit - Exit to real mode.
------------------------------------------------------------------------------
_ret - Simply points to a RET instruction.
------------------------------------------------------------------------------
_getvect - Get interrupt vektor, vektors 0-1fh and 30h are reserved, 31h+
dont exist, but 20h-2fh are IRQ's 0-0fh.
In:
BL - interrupt number
Out:
EAX - 32 bit offset in code
------------------------------------------------------------------------------
_setvect - Set interrupt vektor.
In:
BL - interrupt number
EAX - 32 bit offset in code
------------------------------------------------------------------------------
_getlomem - Get a low memory block.
In:
EAX - size requested
Out:
CF=1 - not enough mem (carry flag set)
EAX - ?
CF=0 - memory allocated (carry flag clear)
EAX - linear pointer to mem
------------------------------------------------------------------------------
_gethimem - Get a high memory block.
In:
EAX - size requested
Out:
CF=1 - not enough mem
EAX - ?
CF=0 - memory allocated
EAX - linear pointer to mem
------------------------------------------------------------------------------
_getmem - Allocate any mem (first cheks low, then high).
In:
EAX - size requested
Out:
CF=1 - not enough mem
EAX - ?
CF=0 - memory allocated
EAX - linear pointer to mem
------------------------------------------------------------------------------
_lomemsize - Get amount of low mem free.
Out:
EAX - number of bytes free
------------------------------------------------------------------------------
_himemsize - Get amount of high mem free.
Out:
EAX - number of bytes free
------------------------------------------------------------------------------
_putdosmsg - Put a '$' terminated DOS string.
In:
EDX -> message (MUST be in low mem).
How to use it:
--------------
It's very simple, you compile START32. Compile with multiple passes to
resolve forward references. Then you link it with your other 32bit modules.
START32 must be the first program in the link list. Try compiling and linking
the example programs, then run them to make sure it runs on your system. The
thing will just color the screen and pop up some numbers, press ESC to return
to DOS.
Some quickie tips on the 386 instruction set:
---------------------------------------------
(This isn't anything new to those of you already familiar with it)
First the extended registers: EAX,EBX,ECX,EDX,ESI,EDI,EBP,ESP,EIP
are all 32bit registers. (No you can't access EIP directly)...
The bit shift instructions, SHL, SHR, RCL, ect... accept immediate values
greater than 1 now. This means 'SHL AX,5' is legal.
The addressing mode has been extended. You can use a combination of ANY 2 of
the 8 general purpose instructions and an immediate value in addressing. Also
one of the registers can be multiplied by 2,4, or 8 right in the address field
of the instruction youre using. So 'MOV BX,[EAX+ECX*4+78]' is legal.
BTW: This is really good because it allows you to use the 'LEA' instruction
to perform quick multiplies. Example: 'LEA EAX,[EAX*4+EAX]' is EAX=EAX*5.
A version of the 'IMUL' instruction doesn't require preloading registers other
than the one(s) you wanna multiply... examples:
IMUL EAX,71 ; EAX=EAX*71
IMUL EAX,ECX,33 ; EAX=ECX*33
You can 'PUSH' immediates... 'PUSH 17983'
I don't feel like explaining the double shift SHLD/SHRD instructions or any
of the BT instructions, so if you don't know em, get a book...
------------------------------------------------------------------------------
Anyways, play with this thing. If you like the flat memory and stuff then
youre free to use this thing in whatever code you do, PD, shareware,
commercial, or whatever...
Any questions or anything, you can contact me on the
Sound Barrier BBS (718)979-6629.
L8r...